export = {};

interface Square {
  kind: "square";
  size: number;
}
interface Rectangle {
  kind: "rectangle";
  width: number;
  height: number;
}
interface Circle {
  kind: "circle";
  radius: number;
}
interface Triangle{
  kind: 'triangle'
}
type Shape = Square | Rectangle | Circle | Triangle;

/** 完整性检查Exhaustiveness checking*/
//当没有涵盖所有可辨识联合的变化时，我们想让编译器可以通知我们
// function area(s: Shape) {
//   switch (s.kind) {
//     case "square": return s.size * s.size;
//     case "rectangle": return s.height * s.width;
//     case "circle": return Math.PI * s.radius ** 2;
//   }
//   // should error here - we didn't handle case "triangle"
// }

/** 法一*/
//启用 --strictNullChecks并且指定一个返回值类型：
function area1(s: Shape): number { // error: returns number | undefined
  switch (s.kind) {
    case "square": return s.size * s.size;
    case "rectangle": return s.height * s.width;
    case "circle": return Math.PI * s.radius ** 2;
    // 因为 switch没有包涵所有情况，所以TypeScript认为这个函数有时候会返回 undefined。
    // 如果你明确地指定了返回值类型为 number，那么你会看到一个错误，因为实际上返回值的类型为 number | undefined。
    // 然而，这种方法存在些取巧 且 --strictNullChecks对旧代码支持不好。
  }
}

/** 法二*/

function assertNever(x: never): never {
  throw new Error("Unexpected object: " + x);
}
function area2(s: Shape) {
  switch (s.kind) {
    case "square": return s.size * s.size;
    case "rectangle": return s.height * s.width;
    case "circle": return Math.PI * s.radius ** 2;
    default: return assertNever(s); // error here if there are missing cases
    //↑ TS2345: Argument of type 'Triangle' is not assignable to parameter of type 'never'.
  }
}
